package com.jessechanrui.template;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Base64;

import org.apache.commons.io.FileUtils;

import cfca.paperless.client.bean.ChannelBean;
import cfca.paperless.client.bean.PdfBean;
import cfca.paperless.client.bean.SealUserInfo;
import cfca.paperless.client.bean.SignLocation;
import cfca.paperless.client.servlet.PaperlessClient;
import cfca.paperless.client.util.PaperlessClientUtil;
import cfca.paperless.client.util.PwdEncryptUtil;
import cfca.paperless.client.util.StrategyUtil;
import cfca.paperless.util.GUID;
import cfca.paperless.util.IoUtil;
import cfca.sadk.extend.session.util.TextUtils;
import cn.com.agree.afa.jcomponent.ErrorCode;
import cn.com.agree.afa.svc.javaengine.AppLogger;
import cn.com.agree.afa.svc.javaengine.TCResult;
import cn.com.agree.afa.svc.javaengine.context.JavaList;

import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;

import galaxy.ide.tech.cpt.Component;
import galaxy.ide.tech.cpt.ComponentGroup;
import galaxy.ide.tech.cpt.InParams;
import galaxy.ide.tech.cpt.OutParams;
import galaxy.ide.tech.cpt.Param;
import galaxy.ide.tech.cpt.Return;
import galaxy.ide.tech.cpt.Returns;


/**
 * PDF工具包
 * @author ztkj-shishaodong
 * @version 1.0 ztkj-shishaodong
 * @ProjectName 通用业务服务平台
 * @Description 运管-2024-6061 关于资金异动类对账单监测规则优化的业务需求
 * @date 2025-04-27 9:32:17
 * @Copyright  版权由上海农商银行所有  
 */
@ComponentGroup(level = "服务", groupName = "PDF工具包", projectName = "CBS", appName = "CBSFHZ")
public class A_PdfTools {
	/**
	 * @category txt文件转pdf文件
	 * @param inputFile 
	 *            入参|txt文件|{@link String}
	 * @param paper
	 *            入参|纸张类型(A4.A8..)|{@link String}
	 * @param size
	 *            入参|字体大小|int
	 * @param coding
	 *            入参|纸张类型(A4.A8..)|{@link String}
	 *            
	 * @since outputFile 出参|输出字符串|{@link String}
	 * @return 0 失败<br/>
	 *         1 成功<br/>
	 * 
	 */
	@InParams(param = {
			@Param(name = "inputFile", comment = "txt文件", type = String.class),
			@Param(name = "paper", comment = "纸张类型(A4.A8..)", type = String.class),
			@Param(name = "size", comment = "字体大小", type = int.class),
			@Param(name = "coding", comment = "字符类型", type = String.class),})
	@OutParams(param = { @Param(name = "outputFile", comment = "输出字符串", type = String.class) })
	@Returns(returns = { @Return(id = "0", desp = "失败"),
			@Return(id = "1", desp = "成功") })
	@Component(label = "txt文件转pdf文件", style = "处理型", type = "同步组件", comment = "txt文件转换为pdf文件，文件类型支持txt、rpt", author = "ztkj-shishaodong", date = "2020-08-17 18:26:45")	
	public static TCResult convertTextToPDF(String inputFile,final String paper,int size,String coding) throws Exception {
		BufferedReader bufferReader = null;
		String outputFile = null;
		
		try {
			final Document pdfDoc;
			// 设置页面大小横向打印
			switch (paper) {
			case "A0":
				pdfDoc=new Document(PageSize.A0.rotate());
				break;
			case "A1":
				pdfDoc=new Document(PageSize.A1.rotate());
				break;
			case "A2":
				pdfDoc=new Document(PageSize.A2.rotate());
				break;
			case "A3":
				pdfDoc=new Document(PageSize.A3.rotate());
				break;
			case "A4":
				pdfDoc=new Document(PageSize.A4);
				break;
			case "A4r":
				pdfDoc=new Document(PageSize.A4.rotate());
				break;	
			case "A5":
				pdfDoc=new Document(PageSize.A5.rotate());
				break;
			case "A6":
				pdfDoc=new Document(PageSize.A6.rotate());
				break;
			case "A7":
				pdfDoc=new Document(PageSize.A7.rotate());
				break;
			case "A8":
				pdfDoc=new Document(PageSize.A8.rotate());
				break;
			case "A9":
				pdfDoc=new Document(PageSize.A9.rotate());
				break;
			case "ARCH_A":
				pdfDoc=new Document(PageSize.ARCH_A.rotate());
				break;
			case "ARCH_B":
				pdfDoc=new Document(PageSize.ARCH_B.rotate());
				break;
			case "ARCH_C":
				pdfDoc=new Document(PageSize.ARCH_C.rotate());
				break;
			case "ARCH_D":
				pdfDoc=new Document(PageSize.ARCH_D.rotate());
				break;
			case "ARCH_E":
				pdfDoc=new Document(PageSize.ARCH_E.rotate());
				break;
			default:
				return TCResult.newFailureResult("PalmErr", "入参\"纸张类型不支持");
			}
			//设置边距
			pdfDoc.setMargins(8f, 8f, 8f, 8f);
			// txt、rpt格式转pdf
			if (-1 != inputFile.indexOf(".txt")) {
				outputFile = inputFile.replaceAll(".txt",".pdf");
			} else {
				outputFile = inputFile.replaceAll(".rpt", ".pdf");
			}
			// 非rpt、txt格式文本不做处理
			if (outputFile == null) {
				return TCResult.newFailureResult("PalmErr", "非rpt、txt格式文本不做处理");
			}
			// 生成pdf实例
			PdfWriter.getInstance(pdfDoc, new FileOutputStream(outputFile)).setPdfVersion(PdfWriter.VERSION_1_7);
			// 设置输出字体和大小
			final BaseFont bfChinese = BaseFont.createFont("/home/afa4j/workspace/conf/simsun.ttc,1", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
			//final BaseFont bfChinese = BaseFont.createFont("STSongStd-Light","UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
			final Font FontChinese = new Font(bfChinese, size, Font.NORMAL);
			// 输入文件
			final File tempFile = new File(inputFile);
			pdfDoc.open();
			if (tempFile.exists()) {
				// txt文本读取
				final InputStreamReader inputStr = new InputStreamReader(new FileInputStream(tempFile), coding);
				bufferReader = new BufferedReader(inputStr);
				String strLine;
				while ((strLine = bufferReader.readLine()) != null) {
					final Paragraph para = new Paragraph(strLine, FontChinese);
					para.setAlignment(Element.ALIGN_JUSTIFIED);
					// pdf文本添加
					pdfDoc.add(para);	
					if(strLine.toString().contains(String.valueOf((char)12))){
						pdfDoc.newPage();
					}
				}
			} else {
				return TCResult.newFailureResult("PalmErr", "no such file exists!");
			}
			pdfDoc.close();
		} catch (final Exception e) {
			e.printStackTrace();
			return TCResult.newFailureResult("PalmErr",e);
		} finally {
			if (bufferReader != null) {
				bufferReader.close();
			}
		}
		return TCResult.newSuccessResult(outputFile);
	}
	/**
	 * @category 报表文件转pdf文件
	 * @param inputFile 
	 *            入参|txt文件|{@link String}
	 * @param paper
	 *            入参|纸张类型(A4.A8..)|{@link String}
	 * @param size
	 *            入参|字体大小|int
	 * @param coding
	 *            入参|纸张类型(A4.A8..)|{@link String}
	 *            
	 * @since outputFile 出参|输出字符串|{@link String}
	 * @return 0 失败<br/>
	 *         1 成功<br/>
	 */
	@InParams(param = {
			@Param(name = "inputFile", comment = "txt文件", type = String.class),
			@Param(name = "paper", comment = "纸张类型(A4.A8..)", type = String.class),
			@Param(name = "size", comment = "字体大小", type = double.class),
			@Param(name = "coding", comment = "字符类型", type = String.class),
			@Param(name = "sizet", comment = "表头字体大小", type = double.class),
			@Param(name = "title", comment = "表头", type = String.class),
			@Param(name = "rude", comment = "加粗", type = String.class)})
	@OutParams(param = { @Param(name = "outputFile", comment = "输出字符串", type = String.class) })
	@Returns(returns = { @Return(id = "0", desp = "失败"),
			@Return(id = "1", desp = "成功") })
	@Component(label = "报表文件转pdf文件", style = "处理型", type = "同步组件", comment = "报表文件转PDF文件，文件类型支持txt、rpt", author = "ztkj-shishaodong", date = "2020-08-17 18:26:45")	
	public static TCResult TxtToPDF(String inputFile,final String paper,double size,String coding,double sizet,String title,String rude) throws Exception {
		BufferedReader bufferReader = null;
		String outputFile = null;

		try {
			final Document pdfDoc;
			// 设置页面大小横向打印
			switch (paper) {
			case "A0":
				pdfDoc=new Document(PageSize.A0);
				break;
			case "A0r":
				pdfDoc=new Document(PageSize.A0.rotate());
				break;
			case "A1":
				pdfDoc=new Document(PageSize.A1);
				break;
			case "A1r":
				pdfDoc=new Document(PageSize.A1.rotate());
				break;
			case "A2":
				pdfDoc=new Document(PageSize.A2);
				break;
			case "A2r":
				pdfDoc=new Document(PageSize.A2.rotate());
				break;
			case "A3":
				pdfDoc=new Document(PageSize.A3);
				break;
			case "A3r":
				pdfDoc=new Document(PageSize.A3.rotate());
				break;
			case "A4":
				pdfDoc=new Document(PageSize.A4);
				break;
			case "A4r":
				pdfDoc=new Document(PageSize.A4.rotate());
				break;	
			case "A5":
				pdfDoc=new Document(PageSize.A5.rotate());
				break;
			case "A6":
				pdfDoc=new Document(PageSize.A6.rotate());
				break;
			case "A7":
				pdfDoc=new Document(PageSize.A7.rotate());
				break;
			case "A8":
				pdfDoc=new Document(PageSize.A8.rotate());
				break;
			case "A9":
				pdfDoc=new Document(PageSize.A9.rotate());
				break;
			case "A10":
				pdfDoc=new Document(PageSize.A10.rotate());
				break;
			case "ARCH_A":
				pdfDoc=new Document(PageSize.ARCH_A.rotate());
				break;
			case "ARCH_B":
				pdfDoc=new Document(PageSize.ARCH_B.rotate());
				break;
			case "ARCH_C":
				pdfDoc=new Document(PageSize.ARCH_C.rotate());
				break;
			case "ARCH_D":
				pdfDoc=new Document(PageSize.ARCH_D.rotate());
				break;
			case "ARCH_E":
				pdfDoc=new Document(PageSize.ARCH_E.rotate());
				break;
			case "LETTER":
				pdfDoc=new Document(PageSize.LETTER.rotate());
				break;
			case "NOTE":
				pdfDoc=new Document(PageSize.NOTE.rotate());
				break;
			case "LEGAL":
				pdfDoc=new Document(PageSize.LEGAL.rotate());
				break;
			case "TABLOID":
				pdfDoc=new Document(PageSize.TABLOID.rotate());
				break;
			case "EXECUTIVE":
				pdfDoc=new Document(PageSize.EXECUTIVE.rotate());
				break;
			case "POSTCARD":
				pdfDoc=new Document(PageSize.POSTCARD.rotate());
				break;
			case "B0":
				pdfDoc=new Document(PageSize.B0);
				break;
			case "B1":
				pdfDoc=new Document(PageSize.B1);
				break;
			case "B2":
				pdfDoc=new Document(PageSize.B2);
				break;
			case "B3":
				pdfDoc=new Document(PageSize.B3);
				break;
			case "B4":
				pdfDoc=new Document(PageSize.B4);
				break;
			case "B4r":
				pdfDoc=new Document(PageSize.B4.rotate());
				break;
			case "B5":
				pdfDoc=new Document(PageSize.B5);
				break;
			case "B6":
				pdfDoc=new Document(PageSize.B6);
				break;
			case "B7":
				pdfDoc=new Document(PageSize.B7);
				break;
			case "B8":
				pdfDoc=new Document(PageSize.B8);
				break;
			case "B9":
				pdfDoc=new Document(PageSize.B9);
				break;
			case "B10":
				pdfDoc=new Document(PageSize.B10);
				break;
			default:
				return TCResult.newFailureResult("PalmErr", "入参\"纸张类型不支持");
			}
			//设置边距
			pdfDoc.setMargins(4f, 4f, 10f, 4f);
			// txt、rpt格式转pdf
			if (-1 != inputFile.indexOf(".txt")) {
				outputFile = inputFile.replaceAll(".txt",".pdf");
			} else {
				outputFile = inputFile.replaceAll(".rpt", ".pdf");
			}
			// 非rpt、txt格式文本不做处理
			if (outputFile == null) {
				return TCResult.newFailureResult("PalmErr", "非rpt、txt格式文本不做处理");
			}
			// 生成pdf实例
			PdfWriter writer = PdfWriter.getInstance(pdfDoc, new FileOutputStream(outputFile));
			writer.setPdfVersion(PdfWriter.VERSION_1_7);
			writer.setInitialLeading(0);
			// 设置输出字体和大小
			final BaseFont bfChinese = BaseFont.createFont("/home/afa4j/workspace/conf/simsun.ttc,1", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
			final BaseFont bfChineseT = BaseFont.createFont("/home/afa4j/workspace/conf/simsun.ttc,1", BaseFont.IDENTITY_H, BaseFont.NOT_CACHED);
			//final BaseFont bfChinese = BaseFont.createFont("STSongStd-Light","UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
			final Font FontChinese = new Font(bfChinese, (float) size, Font.NORMAL);
			final Font FontChineseb = new Font(bfChinese, (float) size, Font.BOLD);
			final Font FontChineseT = new Font(bfChineseT, (float) sizet, Font.BOLD);

			// 输入文件
			final File tempFile = new File(inputFile);
			pdfDoc.open();
			if (tempFile.exists()) {
				// txt文本读取
				final InputStreamReader inputStr = new InputStreamReader(new FileInputStream(tempFile), coding);
				bufferReader = new BufferedReader(inputStr);
				String strLine;
				while ((strLine = bufferReader.readLine()) != null) {
					if(strLine.toString().contains(title)) {
						final Paragraph para = new Paragraph(strLine,FontChineseT);
						para.setAlignment(Element.ALIGN_CENTER);
						pdfDoc.add(para);	
					}else if(strLine.toString().contains(rude)) {
						//格式线
						final Paragraph para = new Paragraph(strLine,FontChineseb);
						para.setAlignment(Element.ALIGN_MIDDLE);
						para.setKeepTogether(true);
						pdfDoc.add(para);	
					}else if(strLine.toString().contains("───────")) {
						//格式线
						final Paragraph para = new Paragraph(strLine,FontChinese);
						para.setAlignment(Element.ALIGN_MIDDLE);
						para.setLeading(6f);
						para.setKeepTogether(true);
						pdfDoc.add(para);	
					}else if(strLine.toString().contains("│")) {
						//格式线
						final Paragraph para = new Paragraph(strLine,FontChinese);
						para.setAlignment(Element.ALIGN_MIDDLE);
						para.setLeading(8f);
						para.setKeepTogether(true);
						pdfDoc.add(para);	
					}else  {
						// pdf文本添加
						final Paragraph para = new Paragraph(strLine,FontChinese);
						para.setAlignment(Element.ALIGN_MIDDLE);
						para.setLeading(12f);
						para.setKeepTogether(true);
						pdfDoc.add(para);	
					}
					
					if(strLine.toString().contains(String.valueOf((char)12))){
						pdfDoc.newPage();
					}
				}
			} else {
				return TCResult.newFailureResult("PalmErr", "no such file exists!");
			}
			pdfDoc.close();
		} catch (final Exception e) {
			e.printStackTrace();
			return TCResult.newFailureResult("PalmErr",e);
		} finally {
			if (bufferReader != null) {
				bufferReader.close();
			}
		}
		return TCResult.newSuccessResult(outputFile);
	}
	/**
	 * @category PDF复合签章
	 * @param host 
	 *            入参|签章地址|{@link String}
	 * @param port
	 *            入参|签章端口|{@link String}
	 * @param bizSerialNo
	 *            入参|业务流水|{@link String}
	 * @param sealCode
	 *            入参|印章编码|{@link String}
	 * @param Keyword
	 *            入参|关键字|{@link String}
	 * @param locationStyle
	 *            入参|位置风格（上:U；下:D；左:L；右:R；中:C）|{@link String}
	 * @param offsetX
	 *            入参|横轴偏移（单位：像素）|{@link int}
	 * @param offsetY
	 *            入参|纵轴偏移（单位：像素）|{@link int}
	 * @param operatorCode
	 *            入参|操作员编码或者机构号|{@link String}
	 * @param channelBeanXml
	 *            入参|渠道编号|{@link String}
	 * @param pdfFilePath
	 *            入参|签章文件路径|{@link String}
	 * @param outputfilePath
	 *            入参|签章返回文件路径|{@link String}
	 * @param impsize
	 *            入参|印章大小|{@link int.String}
	 * @param index
	 *            入参|关键字位置索引（1：第一个位置；2：第二个位置；0：默认全部位置盖章，支持1、2、1-3、3-9格式，如果输入非法数字或者负数当做0处理，如果输入的数字大于关键字数量时就在最后一个位置盖章处理）（可以为空）|{@link int.String}
	 * @since error 出参|签单结果true/false|{@link String}
	 * @return 0 失败<br/>
	 *         1 成功<br/>
	 */
	@InParams(param = {
			@Param(name = "host", comment = "签章地址", type = String.class),
			@Param(name = "port", comment = "签章端口", type = String.class),
			@Param(name = "bizSerialNo", comment = "业务流水", type = String.class),
			@Param(name = "sealCode", comment = "印章编码", type = String.class),
			@Param(name = "sealPassword", comment = "印章密码", type = String.class),
			@Param(name = "Keyword", comment = "关键字", type = String.class),
			@Param(name = "locationStyle", comment = "位置风格（上:U；下:D；左:L；右:R；中:C）", type = String.class),
			@Param(name = "offsetX", comment = "横轴偏移（单位：像素）", type = int.class),
			@Param(name = "offsetY", comment = "纵轴偏移（单位：像素）", type = int.class),
			@Param(name = "operatorCode", comment = "操作员编码或者机构号", type = String.class),
			@Param(name = "channelBeanXml", comment = "渠道编号", type = String.class),
			@Param(name = "pdfFilePath", comment = "签章文件路径", type = String.class),
			@Param(name = "outputfilePath", comment = "签章返回文件路径", type = String.class),
			@Param(name = "impsize", comment = "印章大小", type = int.class),
			@Param(name = "index", comment = "关键字位置索引（1：第一个位置；2：第二个位置；0：默认全部位置盖章，支持1、2、1-3、3-9格式，如果输入非法数字或者负数当做0处理，如果输入的数字大于关键字数量时就在最后一个位置盖章处理）（可以为空） ", type = int.class),})
	@OutParams(param = { @Param(name = "error", comment = "签单结果true/false", type = String.class) })
	@Returns(returns = { @Return(id = "0", desp = "失败"),
			@Return(id = "1", desp = "成功") })
	@Component(label = " PDF复合签章", style = "处理型", type = "同步组件", comment = "PDF复合签章", author = "ztkj-shishaodong", date = "2020-09-08 18:26:45")	
	public static TCResult CompoundSealAutoPdf(String host,String port,String bizSerialNo,String sealCode,String sealPassword,String Keyword,
			String locationStyle,int offsetX,int offsetY,String operatorCode,String channelBeanXml,String pdfFilePath,String outputfilePath,
			int impsize,String index) throws Exception {
		try {
			String url = "http://" + host +":" + port + "/PaperlessServer/PaperlessServlet";
			AppLogger.info(url);
			PaperlessClient clientBean = new PaperlessClient(url, 10000, 60000);// 无纸化基本接口的访问URLz
			// 如下为PDF数据策略文件
			// ************************************************************
			// 服务端能够读取到的ftp文件e路径
			byte[] pdfFileData = FileUtils.readFileToByteArray(new File(pdfFilePath));
			String savedPdfId = "";
			// 如下为加盖一个普通企业印章的策略
			// 印章编码和印章密码，需要在无纸化管理系统中添加此印章的信息，登录管理页面->选择电子印章管理->选择印章管理->添加印章信息（需要先添加相应的印模信息和印章证书信息）
			sealPassword = PwdEncryptUtil.encrypto(sealPassword);
			// 签章杂项信息
			// ************************************************************
			SealUserInfo sealUserInfo = new SealUserInfo();// 签章人，签章地点，签章理由,可为空
			// 设置印章显示大小，可以不设置。比如：100，代表100px。比如需要把章显示为4cm（圆章且DPI为96）时，传入151即可。（并且imageScale配置为0.87）
			sealUserInfo.setSealImageSize(impsize);
			// 签章类型（不能为空），1=空白标签签章,2=坐标签章,3=关键字签章，4=位置标识
			// 3=按关键字签章
			// 关键字，按关键字签章时不能为空；
			// 位置风格：（上:U；下:D；左:L；右:R；中:C）；默认：C；
			// 横轴偏移，默认为0（单位：像素）；纵轴偏移，默认为0（单位：像素）
			locationStyle=(locationStyle == null || locationStyle.equals(""))?"R":locationStyle ;
			SignLocation signLocation = new SignLocation(Keyword, locationStyle, offsetX==0?5:offsetX, offsetY==0?1:offsetY);
			// 关键字位置索引（1：第一个位置；2：第二个位置；0：默认全部位置盖章，支持1、2、1-3、3-9格式，如果输入非法数字或者负数当做0处理，如果输入的数字大于关键字数量时就在最后一个位置盖章处理）
			signLocation.setKeywordPositionIndex(index);
			// 生成签章策略文件
			//System.out.println("signLocations:"+signLocations);
			String sealStrategyXml = StrategyUtil.createSealStrategyXml(sealCode, sealPassword, sealUserInfo, signLocation);
			String compoundSealStrategyXml = new StringBuilder().append("<List>").append(sealStrategyXml).append("</List>").toString();
			// 获取时间戳的方式。默认值为0。0：实时访问CFCA 时间戳服务；1：使用从CFCA购置并在本地部署的时间戳服务器产品；
			String timestampChannel = "0";
			//密码是否密文传输，默认为false-原文传输，true-密文传输
			String isEncrypt = "true";
			String systemNo = GUID.generateId();
			AppLogger.info(systemNo);
			byte[] sealedPdfData = clientBean.sealAutoPdf(systemNo, pdfFileData, savedPdfId, compoundSealStrategyXml, operatorCode, channelBeanXml, timestampChannel, isEncrypt);
			String errorRsString = PaperlessClientUtil.isError(sealedPdfData);
			// 处理结果为正常，保存签章后的PDF文件到本地目录下
			if ("".equals(errorRsString)) {
				PdfBean pdfBean = new PdfBean();
				if (pdfBean.isReturnPdfOrNot()) {
					IoUtil.write(outputfilePath, sealedPdfData);
					return TCResult.newSuccessResult("true");
				} else {
					AppLogger.info(new String(sealedPdfData, "UTF-8"));
					return TCResult.newFailureResult("PalmErr","false");
				}

			} else {
				// 处理结果为异常，打印出错误码和错误信息
				AppLogger.info(new String(sealedPdfData, "UTF-8"));
				return TCResult.newFailureResult("PalmErr",errorRsString);
			}
		} catch (java.io.FileNotFoundException File) {
			// TODO: handle exception
			return TCResult.newFailureResult("PalmErr","文件不存在："+File);
		}catch (Exception e) {
			// TODO: handle exception
			return TCResult.newFailureResult("PalmErr",e);
		}
	}
	/**
	 * @category PDF复合签章-单据存放
	 * @param host 
	 *            入参|签章地址|{@link String}
	 * @param port
	 *            入参|签章端口|{@link String}
	 * @param bizSerialNo
	 *            入参|业务流水|{@link String}
	 * @param sealCode
	 *            入参|印章编码|{@link String}
	 * @param Keyword
	 *            入参|关键字|{@link String}
	 * @param operatorCode
	 *            入参|操作员编码或者机构号|{@link String}
	 * @param channelBeanXml
	 *            入参|渠道编号|{@link String}
	 * @param pdfFilePath
	 *            入参|签章文件路径|{@link String}
	 * @param outputfilePath
	 *            入参|签章返回文件路径|{@link String}
	 * @param impsize
	 *            入参|印章大小|{@link int.String}
	 * @since error 出参|签单结果true/false|{@link String}
	 * @return 0 失败<br/>
	 *         1 成功<br/>
	 */
	@InParams(param = {
			@Param(name = "host", comment = "签章地址", type = String.class),
			@Param(name = "port", comment = "签章端口", type = String.class),
			@Param(name = "bizSerialNo", comment = "业务流水", type = String.class),
			@Param(name = "sealCode", comment = "印章编码", type = String.class),
			@Param(name = "sealPassword", comment = "印章密码", type = String.class),
			@Param(name = "Keyword", comment = "关键字", type = String.class),
			@Param(name = "operatorCode", comment = "操作员编码或者机构号", type = String.class),
			@Param(name = "channelBeanXml", comment = "渠道编号", type = String.class),
			@Param(name = "pdfFilePath", comment = "签章文件路径", type = String.class),
			@Param(name = "outputfilePath", comment = "签章返回文件路径", type = String.class),
			@Param(name = "impsize", comment = "印章大小", type = int.class),})
	@OutParams(param = { @Param(name = "error", comment = "签单结果true/false", type = String.class) })
	@Returns(returns = { @Return(id = "0", desp = "失败"),
			@Return(id = "1", desp = "成功") })
	@Component(label = " PDF复合签章-单据存放", style = "处理型", type = "同步组件", comment = "PDF复合签章-单据存放", author = "ztkj-shishaodong", date = "2020-09-08 18:26:45")	
	public static TCResult CompoundSealAutoPdfOutput(String host,String port,String bizSerialNo,String sealCode,String sealPassword,String Keyword,
			String operatorCode,String channelBeanXml,String pdfFilePath,String outputfilePath,int impsize) throws Exception {
		try {
			String url = "http://" + host +":" + port + "/PaperlessServer/PaperlessServlet";
			AppLogger.info(url);
			PaperlessClient clientBean = new PaperlessClient(url, 10000, 60000);// 无纸化基本接口的访问URLz
			// 如下为PDF数据策略文件
			// ************************************************************


			// 保存到临时PDF表中的pdfId，符合唯一约束（可以为空）pdfId值长度为 18-32位
			// 不为空时，则在服务端的临时PDF表[TEMP_FILE_PDF]中，指定表中字段PDF_ID为此值，保存PDF文件数据，只保留1个小时，超时则清除。
			// 为空时，则不会在服务端保存PDF文件数据。
			String savedPdfId = GUID.generateId();

			boolean returnPdfOrNot = false;// 是否返回pdf，默认为true，取值false时，OutputFilePath不能为空			

			PdfBean pdfBean = new PdfBean();

			pdfBean.setInputFilePath(pdfFilePath);// pdf地址，支持文件路径、ftp、http、swift，Pdf为空时生效
			//文件转换
			File file =new File(pdfFilePath);
			FileInputStream io=new FileInputStream(file);
			byte[] buffy=new byte[(int)file.length()];
			io.read(buffy);
			io.close();
			pdfBean.setPdf(Base64.getEncoder().encodeToString(buffy));
			pdfBean.setSavedPdfId(savedPdfId);// 保存到临时PDF表中的pdfId，符合唯一约束（可以为空）
			pdfBean.setOutputFilePath(outputfilePath);// 单据存放地址，可以为空
			pdfBean.setReturnPdfOrNot(returnPdfOrNot);// 是否返回pdf，默认为true，取值false时，OutputFilePath不能为空

			pdfBean.setBizSerialNo(bizSerialNo);// 业务流水号, 可以为空
			channelBeanXml = new ChannelBean(channelBeanXml).toString();//渠道编码
			String pdfBeanXml = PaperlessClientUtil.buildPdfBeanXml(pdfBean);
			// ************************************************************

			String multiData = "";// multiData=需要合成到pdf的多媒体数据（内容格式参考如下示例），可以为空

			// 如下为加盖一个普通企业印章的策略
			// 印章编码和印章密码，需要在无纸化管理系统中添加此印章的信息，登录管理页面->选择电子印章管理->选择印章管理->添加印章信息（需要先添加相应的印模信息和印章证书信息）
			sealPassword = PwdEncryptUtil.encrypto(sealPassword);

			// 签章杂项信息
			// ************************************************************
			SealUserInfo sealUserInfo = new SealUserInfo("","","");// 签章人，签章地点，签章理由,可为空

			// 设置印章显示大小，可以不设置。比如：100，代表100px。比如需要把章显示为4cm（圆章且DPI为96）时，传入151即可。（并且imageScale配置为0.87）
			sealUserInfo.setSealImageSize(impsize);

			// 签章类型（不能为空），1=空白标签签章,2=坐标签章,3=关键字签章，4=位置标识
			// 3=按关键字签章
			// 关键字，按关键字签章时不能为空；
			// 位置风格：（上:U；下:D；左:L；右:R；中:C）；默认：C；
			// 横轴偏移，默认为0（单位：像素）；纵轴偏移，默认为0（单位：像素）
			SignLocation signLocation = new SignLocation(Keyword, "R", 5, 1);
			// 关键字位置索引（1：第一个位置；2：第二个位置；0：默认全部位置盖章，支持1、2、1-3、3-9格式，如果输入非法数字或者负数当做0处理，如果输入的数字大于关键字数量时就在最后一个位置盖章处理）
			signLocation.setKeywordPositionIndex("1");

			// 生成签章策略文件
			//System.out.println("signLocations:"+signLocations);
			String sealStrategyXml = StrategyUtil.createSealStrategyXml(sealCode, sealPassword, sealUserInfo, signLocation);

			String compoundSealStrategyXml = new StringBuilder().append("<List>").append(sealStrategyXml).append("</List>").toString();

			// 获取场景证书的方式，与证据证书签章策略文件配合使用。默认值为0。0：实时从CFCA CA服务申请下载场景证书；1：使用从CFCA CA服务预先申请下载并存储在本地的场景证书；
			String sceneCertChannel = "0";

			// 获取时间戳的方式。默认值为0。0：实时访问CFCA 时间戳服务；1：使用从CFCA购置并在本地部署的时间戳服务器产品；
			String timestampChannel = "0";

			//密码是否密文传输，默认为false-原文传输，true-密文传输
			String isEncrypt = "true";
			String systemNo = GUID.generateId();
			AppLogger.info(systemNo);
			byte[] sealedPdfData = clientBean.compoundSealAutoPdf(systemNo, pdfBeanXml, multiData, compoundSealStrategyXml, operatorCode, channelBeanXml, sceneCertChannel,timestampChannel, isEncrypt);

			String errorRsString = PaperlessClientUtil.isError(sealedPdfData);	

			// 处理结果为正常，保存签章后的PDF文件到本地目录下
			if ("".equals(errorRsString)) {
				if (pdfBean.isReturnPdfOrNot()) {
					IoUtil.write(outputfilePath, sealedPdfData);
				} else {
					AppLogger.info(new String(sealedPdfData, "UTF-8"));
				}
				return TCResult.newSuccessResult("true");
			} else {		
				// 处理结果为异常，打印出错误码和错误信息
				AppLogger.info(new String(sealedPdfData, "UTF-8"));
				return TCResult.newFailureResult("PalmErr",errorRsString);
			}
		} catch (java.io.FileNotFoundException File) {
			// TODO: handle exception
			return TCResult.newFailureResult("PalmErr","文件不存在："+File);
		}catch (Exception e) {
			// TODO: handle exception
			return TCResult.newFailureResult("PalmErr",e);
		}
	}

	/**
	 * @category PDF复合签章（下标）
	 * @param host 
	 *            入参|签章地址|{@link String}
	 * @param port
	 *            入参|签章端口|{@link String}
	 * @param bizSerialNo
	 *            入参|业务流水|{@link String}
	 * @param sealCode
	 *            入参|印章编码|{@link String}
	 * @param type
	 *            入参|签章类型（不能为空）,1=空白标签签章,2=坐标签章,3=关键字签章，4=位置标识|{@link String}
	 * @param Keyword
	 *            入参|关键字|{@link String}
	 * @param coord
	 *            入参|关键字位置索引（1：第一个位置；2：第二个位置；0：默认全部位置盖章，支持1、2、1-3、3-9格式，如果输入非法数字或者负数当做0处理，如果输入的数字大于关键字数量时就在最后一个位置盖章处理|{@link String}
	 * @param BizLoc
	 *            入参|签章位置标识编码|{@link String}
	 * @param operatorCode
	 *            入参|操作员编码或者机构号|{@link String}
	 * @param channelBeanXml
	 *            入参|渠道编号|{@link String}
	 * @param pdfFilePath
	 *            入参|签章文件路径|{@link String}
	 * @param outputfilePath
	 *            入参|签章返回文件路径|{@link String}
	 * @param impsize
	 *            入参|印章大小|{@link String}
	 * @since error 出参|签单结果true/false|{@link String}
	 * @return 0 失败<br/>
	 *         1 成功<br/>
	 */
	@InParams(param = {
			@Param(name = "host", comment = "签章地址", type = String.class),
			@Param(name = "port", comment = "签章端口", type = String.class),
			@Param(name = "bizSerialNo", comment = "业务流水", type = String.class),
			@Param(name = "sealCode", comment = "印章编码", type = String.class),
			@Param(name = "sealPassword", comment = "印章密码", type = String.class),
			@Param(name = "type", comment = "签章类型（不能为空），1=空白标签签章,2=坐标签章,3=关键字签章，4=位置标识", type = int.class),
			@Param(name = "xpe", comment = "左侧的x坐标（单位：像素）", type = int.class),
			@Param(name = "ype", comment = "左侧的y坐标（单位：像素）", type = int.class),
			@Param(name = "page", comment = "页数", type = int.class),
			@Param(name = "Keyword", comment = "关键字", type = String.class),
			@Param(name = "coord", comment = "关键字位置索引（1：第一个位置；2：第二个位置；0：默认全部位置盖章，支持1、2、1-3、3-9格式，如果输入非法数字或者负数当做0处理，如果输入的数字大于关键字数量时就在最后一个位置盖章处理", type = String.class),
			@Param(name = "BizLoc", comment = "签章位置标识编码", type = String.class),
			@Param(name = "operatorCode", comment = "操作员编码或者机构号", type = String.class),
			@Param(name = "channelBeanXml", comment = "渠道编号", type = String.class),
			@Param(name = "pdfFilePath", comment = "签章文件路径", type = String.class),
			@Param(name = "outputfilePath", comment = "签章返回文件路径", type = String.class),
			@Param(name = "impsize", comment = "印章大小", type = int.class),})
	@OutParams(param = { @Param(name = "error", comment = "签单结果true/false", type = String.class) })
	@Returns(returns = { @Return(id = "0", desp = "失败"),
			@Return(id = "1", desp = "成功") })
	@Component(label = "PDF复合签章（下标）", style = "处理型", type = "同步组件", comment = "PDF复合签章", author = "ztkj-shishaodong", date = "2020-09-08 18:26:45")	
	public static TCResult CompoundSealAutoPdfxb(String host,String port,String bizSerialNo,String sealCode,String sealPassword,
			int type,int xpe,int ype,int page,String Keyword,String coord,String BizLoc,String operatorCode,String channelBeanXml,String pdfFilePath,
			String outputfilePath,int impsize) throws Exception {
		try {
			String url = "http://" + host +":" + port + "/PaperlessServer/PaperlessServlet";
			AppLogger.info(url);
			PaperlessClient clientBean = new PaperlessClient(url, 10000, 60000);// 无纸化基本接口的访问URLz
			// 如下为PDF数据策略文件
			// ************************************************************
			// 服务端能够读取到的ftp文件e路径
			byte[] pdfFileData = FileUtils.readFileToByteArray(new File(pdfFilePath));
			String savedPdfId = "";
			// 如下为加盖一个普通企业印章的策略
			// 印章编码和印章密码，需要在无纸化管理系统中添加此印章的信息，登录管理页面->选择电子印章管理->选择印章管理->添加印章信息（需要先添加相应的印模信息和印章证书信息）
			sealPassword = PwdEncryptUtil.encrypto(sealPassword);
			// 签章杂项信息
			// ************************************************************
			SealUserInfo sealUserInfo = new SealUserInfo();// 签章人，签章地点，签章理由,可为空
			// 设置印章显示大小，可以不设置。比如：100，代表100px。比如需要把章显示为4cm（圆章且DPI为96）时，传入151即可。（并且imageScale配置为0.87）
			sealUserInfo.setSealImageSize(impsize);
			// 签章类型（不能为空），1=空白标签签章,2=坐标签章,3=关键字签章，4=位置标识
			SignLocation signLocation=null;
			switch (type) {
			case 1:
				// 1=按空白标签域签章
		        signLocation = new SignLocation();
		        signLocation.setType("1");// 1=空白标签签章
				break;
			case 2:
				// 2=按坐标签章
		        // 页数，按坐标签章时不能为空；
		        // 左侧的x坐标（单位：像素）；左侧的y坐标（单位：像素）；
		        signLocation = new SignLocation(page,xpe, ype);
				break;
			case 3:
				// 3=按关键字签章
				// 关键字，按关键字签章时不能为空；
				// 位置风格：（上:U；下:D；左:L；右:R；中:C）；默认：C；
				// 横轴偏移，默认为0（单位：像素）；纵轴偏移，默认为0（单位：像素）
				signLocation = new SignLocation(Keyword, "R", 5, 1);
				// 关键字位置索引（1：第一个位置；2：第二个位置；0：默认全部位置盖章，支持1、2、1-3、3-9格式，如果输入非法数字或者负数当做0处理，如果输入的数字大于关键字数量时就在最后一个位置盖章处理）
				signLocation.setKeywordPositionIndex(coord);
				break;
			case 4:
				// 4=按位置标识签章（需要提前在服务端管理页面上登录业务模板和签章位置标识信息）
		        signLocation = new SignLocation(BizLoc);// 签章位置标识编码
				break;
			default:
				return TCResult.newFailureResult("PalmErr","签章类型错误");
			}


			// 生成签章策略文件
			//System.out.println("signLocations:"+signLocations);
			String sealStrategyXml = StrategyUtil.createSealStrategyXml(sealCode, sealPassword, sealUserInfo, signLocation);
			String compoundSealStrategyXml = new StringBuilder().append("<List>").append(sealStrategyXml).append("</List>").toString();
			// 获取时间戳的方式。默认值为0。0：实时访问CFCA 时间戳服务；1：使用从CFCA购置并在本地部署的时间戳服务器产品；
			String timestampChannel = "0";
			//密码是否密文传输，默认为false-原文传输，true-密文传输
			String isEncrypt = "true";
			String systemNo = GUID.generateId();
			AppLogger.info(systemNo);
			byte[] sealedPdfData = clientBean.sealAutoPdf(systemNo, pdfFileData, savedPdfId, compoundSealStrategyXml, operatorCode, channelBeanXml, timestampChannel, isEncrypt);
			String errorRsString = PaperlessClientUtil.isError(sealedPdfData);
			// 处理结果为正常，保存签章后的PDF文件到本地目录下
			if ("".equals(errorRsString)) {
				PdfBean pdfBean = new PdfBean();
				if (pdfBean.isReturnPdfOrNot()) {
					IoUtil.write(outputfilePath, sealedPdfData);
					return TCResult.newSuccessResult("true");
				} else {
					AppLogger.info(new String(sealedPdfData, "UTF-8"));
					return TCResult.newFailureResult("PalmErr","false");
				}

			} else {
				// 处理结果为异常，打印出错误码和错误信息
				AppLogger.info(new String(sealedPdfData, "UTF-8"));
				return TCResult.newFailureResult("PalmErr",errorRsString);
			}
		} catch (java.io.FileNotFoundException File) {
			return TCResult.newFailureResult("PalmErr","文件不存在："+File);
		}catch (Exception e) {
			return TCResult.newFailureResult("PalmErr",e);
		}
	}
	
	/**
	 * A文件合并
	 * 
	 * @param fileList
	 *            入参|文件名列表|
	 *            {@link cn.com.agree.afa.svc.javaengine.context.JavaList}
	 * @param filepatch
	 *            入参|版本日期|{@link String}
	 * @param ver
	 *            入参|合并文件路径|{@link String}
	 * @param area
	 *            入参|适用区域|{@link String}
	 * @return 0 失败<br/>
	 *         1 成功<br/>
	 * @使用范例 :
	 * @example :join(["D:/test.txt","D:/user.txt"])
	 * @example :join(["D:/test.txt","D:/user.txt","D:/server.txt"])
	 * @example 
	 *          :join(["D:/test.txt","D:/user.txt","D:/server.txt","D:/temp.txt"]
	 *          )
	 */
	@InParams(param = {
			@Param(name = "fileList", comment = "文件名列表", type = cn.com.agree.afa.svc.javaengine.context.JavaList.class),
			@Param(name = "filepatch", comment = "合并文件路径", type = String.class),
			@Param(name = "ver", comment = "版本日期", type = String.class),
			@Param(name = "area", comment = "适用区域", type = String.class) })
	@OutParams(param = {})
	@Returns(returns = { @Return(id = "0", desp = "失败"),
			@Return(id = "1", desp = "成功") })
	@Component(label = "A文件合并", style = "判断型", type = "同步组件", comment = "fileList[0]表示目标文件,后续文件合并到目标文件中", date = "Thu Jul 16 11:44:33 CST 2015")
	public static TCResult A_File_Join(JavaList fileList,String filepatch, String ver,String area) {
		if (fileList == null || fileList.size() < 2) {
			return TCResult.newFailureResult(ErrorCode.AGR,
					"参数不能为null且文件个数不能小于2");
		}
		if (((String) fileList.get(0)) == null
				|| ((String) fileList.get(0)).length() == 0) {
			return TCResult.newFailureResult(ErrorCode.PARAM,
					"列表第一个元素不能为null或者为空字符串");
		}
		File[] files=new File[fileList.size()];
		int f=0;
		for(Object fs : fileList){
			String fname = (String) fs;
			files[f]=new File(fname);
			f++;
		}

		File dstFile =new File(filepatch);
		String fileName = null;
		AppLogger.info("filepatch:"+filepatch);
		BufferedInputStream in = null;
		BufferedOutputStream out = null;

		byte[] buf = new byte[1024];
		try {
			
			out = new BufferedOutputStream(new FileOutputStream(dstFile));

			for (Object item : fileList) {
				fileName = (String) item;
				AppLogger.info("item:"+item.toString());
				in=new BufferedInputStream(new FileInputStream(fileName));
				int len;
				while ((len = in.read(buf)) >0) {
					out.write(buf, 0, len);
				}
				out.flush();
				in.close();
			}
			for (int i = 0; i < files.length; i++) {
				AppLogger.info("files"+i+":"+files[i]);
				files[i].delete();
			}
			return TCResult.newSuccessResult();
		} catch (Exception e) {
			return TCResult.newFailureResult(ErrorCode.FILECTL, e);
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					AppLogger.error(e);
				}
				in = null;
			}
			if (out != null) {
				try {
					out.close();
				} catch (IOException e) {
					AppLogger.error(e);
				}
				out = null;
			}
		}
	}

}
